﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MapGIS.GeoDataBase;
using MapGIS.GISControl;
using MapGIS.GeoObjects.Geometry;
using MapGIS.GeoMap;
using MapGIS.GeoObjects.SpatialRef;
using MapGIS.GeoObjects;
using System.Xml;
using System.Reflection;
using System.IO;
using MapGIS.GeoObjects.Info;


namespace Wcf_MapFrame
{
    class MapFrame
    {
        private static ScaleType GetScaleType(Int32 scale)
        {
            if (scale >= 5000 && scale < 10000)
                return ScaleType.Scale_5000;
            else if (scale >= 10000 && scale < 25000)
                return ScaleType.Scale_1w;
            else if (scale >= 25000 && scale < 50000)
                return ScaleType.Scale_2w5;
            else if (scale >= 50000 && scale < 100000)
                return ScaleType.Scale_5w;
            else if (scale >= 100000 && scale < 200000)
                return ScaleType.Scale_10w;
            else if (scale >= 200000 && scale < 250000)
                return ScaleType.Scale_20w;
            else if (scale >= 250000 && scale < 500000)
                return ScaleType.Scale_25w;
            else if (scale >= 500000 && scale < 1000000)
                return ScaleType.Scale_50w;
            else if (scale >= 1000000)
                return ScaleType.Scale_100w;
            return ScaleType.Scale_Unkown;
        }


        public static string GetMapFrame(Int32 scale, Rect range, string srs, string title)
        {
            string StrRt = "";
            ScaleType scType = GetScaleType(scale);
            DataBase tempGDB = DataBase.OpenTempDB();
            string srsName = TransSRSNameByXml(srs, true);
            if (string.IsNullOrEmpty(srsName))
                return "";
            int srsID = tempGDB.SpatialRefMng.GetID(srsName);
            SRefData refData = tempGDB.SpatialRefMng.Get(srsID);
            if (refData == null)
                return "";

            SRefLenUnit unit = SRefLenUnit.DMS;
            if (refData.ProjType == SRefPrjType.LonLat)
                unit = refData.AngUnit;
            else
                unit = refData.Unit;

            Random r = new Random();
            string clsName = "fame" + r.Next(1000);
            SFeatureCls frameReg = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            SFeatureCls frameLin = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            SFeatureCls framePnt = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            AnnotationCls frameAnn = tempGDB.GetXClass(XClsType.ACls) as AnnotationCls;
            if (frameReg == null || frameLin == null || framePnt == null || frameAnn == null)
                goto end;

            if (frameReg.Create(clsName + "_Reg", GeomType.Reg, 0, 0, null) <= 0)
                goto end;
            if (frameLin.Create(clsName + "_Lin", GeomType.Lin, 0, 0, null) <= 0)
                goto end;
            if (framePnt.Create(clsName + "_Pnt", GeomType.Pnt, 0, 0, null) <= 0)
                goto end;
            if (frameAnn.Create(clsName + "_Ann", AnnType.Text, 0, 0, null) <= 0)
                goto end;
            CommonMapDecoration mapDecoration = new CommonMapDecoration();
            DataCanvas canvas = new DataCanvas(frameReg, frameLin, framePnt, frameAnn);
            mapDecoration.Init(refData, range, unit, scale);
            CommonDecorationInfo info = mapDecoration.GetDefaultInfo(scale);
            //主标题
            info.MainTitle = title;
            //左下角标注信息
            info.LBNote = srsName;//"1980西安坐标系，1985国家高程基准；等高距为5m";
            //右下角标注信息
            info.RBNote = "";
            //副标题
            info.SubTitle = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMin, scType, true, true);
            //接图表下中图幅号
            info.LinkTableCB = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMin, scType, true, false);
            //接图表上中图幅号
            info.LinkTableCT = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMax, scType, true, true);
            //接图表左下图幅号
            info.LinkTableLB = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMin, scType, false, false);
            //接图表中左图幅号
            info.LinkTableLC = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMin, scType, false, true);
            //接图表左上图幅号
            info.LinkTableLT = FrmNoUtility.CalFrmNoByLonLat(range.XMin, range.YMax, scType, false, true);
            //接图表右下图幅号
            info.LinkTableRB = FrmNoUtility.CalFrmNoByLonLat(range.XMax, range.YMin, scType, true, false);
            //接图表中右图幅号
            info.LinkTableRC = FrmNoUtility.CalFrmNoByLonLat(range.XMax, range.YMin, scType, true, true);
            //接图表右上图幅号
            info.LinkTableRT = FrmNoUtility.CalFrmNoByLonLat(range.XMax, range.YMax, scType, true, true);
            //设置整饰信息
            mapDecoration.SetInfo(info);
            if (!mapDecoration.Make(canvas))
                goto end;
            StrRt += "{ \"type\": \"FeatureCollection\",";
            StrRt += TranGeoJson.TransSRS(srs);
            StrRt += ",\"features\": [";
            StrRt += TransCls2GeoJson(frameReg);
            StrRt += TransCls2GeoJson(frameLin);
            StrRt += TransCls2GeoJson(framePnt);
            StrRt += TransACls2GeoJson(frameAnn);
            if (StrRt[StrRt.Length - 1] == ',')
                StrRt = StrRt.Substring(0, StrRt.Length - 1);
            StrRt += "]}";
        end:
            if (frameReg != null)
                frameReg.Close();
            if (frameLin != null)
                frameLin.Close();
            if (framePnt != null)
                framePnt.Close();
            if (frameAnn != null)
                frameAnn.Close();
            DataBase.FreeTempDB(tempGDB);
            return StrRt;
        }

        public static string GetMapGrid(Int32 scale, Rect range, string srs, string title)
        {
            string StrRt = "";
            ScaleType scType = GetScaleType(scale);
            DataBase tempGDB = DataBase.OpenTempDB();
            string srsName = TransSRSNameByXml(srs, true);
            if (string.IsNullOrEmpty(srsName))
                return "";
            int srsID = tempGDB.SpatialRefMng.GetID(srsName);
            SRefData refData = tempGDB.SpatialRefMng.Get(srsID);
            if (refData == null)
                return "";

            SRefLenUnit unit = SRefLenUnit.DMS;
            if (refData.ProjType == SRefPrjType.LonLat)
                unit = refData.AngUnit;
            else
                unit = refData.Unit;

            Random r = new Random();
            string clsName = "fame" + r.Next(1000);
            SFeatureCls frameReg = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            SFeatureCls frameLin = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            SFeatureCls framePnt = tempGDB.GetXClass(XClsType.SFCls) as SFeatureCls;
            AnnotationCls frameAnn = tempGDB.GetXClass(XClsType.ACls) as AnnotationCls;
            if (frameReg == null || frameLin == null || framePnt == null || frameAnn == null)
                goto end;

            if (frameReg.Create(clsName + "_Reg", GeomType.Reg, 0, 0, null) <= 0)
                goto end;
            if (frameLin.Create(clsName + "_Lin", GeomType.Lin, 0, 0, null) <= 0)
                goto end;
            if (framePnt.Create(clsName + "_Pnt", GeomType.Pnt, 0, 0, null) <= 0)
                goto end;
            if (frameAnn.Create(clsName + "_Ann", AnnType.Text, 0, 0, null) <= 0)
                goto end;

            MapGrid Grid = new MapGrid();
            Grid.SetSrs(refData);
            Grid.SetRange(range, (byte)unit);
            Grid.Scale = scale;
            GridStyle gridStyle = new GridStyle();
            GridInfo StyleInfo = new GridInfo();

            StyleInfo.Coord = 1;
            StyleInfo.Cxy = 0;//倍数

            StyleInfo.Graduate = 1;
            StyleInfo.GraduateClr = 1;
            StyleInfo.GraduateLen = 6;
            StyleInfo.GraduatePos = 0;
            StyleInfo.GraduateWid = (float)0.1;

            StyleInfo.LineClr = 1;
            StyleInfo.LineCrossLen = (float)0.5;
            StyleInfo.LineEx = 0;

            //StyleInfo.Nx = 4;
            //StyleInfo.Ny = 4;
            StyleInfo.Dx = AdjustGridSpace(range.XMax - range.XMin);
            StyleInfo.Dy = AdjustGridSpace(range.YMax - range.YMin);
            StyleInfo.Type = 1;
            StyleInfo.Line = 2;
            StyleInfo.MidNote = 0;

            CoordInfo coordInfo = new CoordInfo();
            coordInfo.DigitX = 0;
            coordInfo.DigitY = 0;
            coordInfo.Unit = (byte)2; //注记显示为度
            coordInfo.Note = 0;
            coordInfo.InfoX = coordInfo.InfoY = 0;
            coordInfo.SepX = 0;
            coordInfo.SepY = 0;
            
            TextAnnInfo anninfo = new TextAnnInfo();
            anninfo.Width = 5;
            anninfo.Height = 5;
            coordInfo.SetInfo(anninfo);
            coordInfo.SetInfoSpe(anninfo);
            coordInfo.SetInfoZone(anninfo);
            CoordPos pos = new CoordPos();
            StyleInfo.SetPosX(pos);
            StyleInfo.SetPosY(pos);
            StyleInfo.SetCoord(coordInfo);
            StyleInfo.SetMidNoteInfo(anninfo);

            gridStyle.SetInfo(StyleInfo);

            Grid.SetStyle(gridStyle);
            DataCanvas canvas = new DataCanvas(frameReg, frameLin, framePnt, frameAnn);
            Grid.Make(canvas);

            StrRt += "{ \"type\": \"FeatureCollection\",";
            StrRt += TranGeoJson.TransSRS(srs);
            StrRt += ",\"features\": [";
            StrRt += TransCls2GeoJson(frameReg);
            StrRt += TransCls2GeoJson(frameLin);
            StrRt += TransCls2GeoJson(framePnt);
            StrRt += TransACls2GeoJson(frameAnn);
            if (StrRt[StrRt.Length - 1] == ',')
                StrRt = StrRt.Substring(0, StrRt.Length - 1);
            StrRt += "]}";
        end:
            if (frameReg != null)
                frameReg.Close();
            if (frameLin != null)
                frameLin.Close();
            if (framePnt != null)
                framePnt.Close();
            if (frameAnn != null)
                frameAnn.Close();
            DataBase.FreeTempDB(tempGDB);
            return StrRt;
        }

        public static string TransCls2GeoJson(SFeatureCls sfcls)
        {
            if (sfcls == null)
                return "";
            QueryDef qd = new QueryDef();
            qd.CursorType = SetCursorType.ForwardCacheSpa;
            RecordSet recordSet = sfcls.Select(qd);
            if (recordSet == null)
                return "";
            string strRt = "";
            recordSet.MoveFirst();
            while (!recordSet.IsEOF)
            {
                IGeometry geo = recordSet.Geometry;
                switch (geo.Type)
                {
                    case GeometryType.Point:
                        GeoPoint point = geo as GeoPoint;
                        strRt += TranGeoJson.TransPoint(point);
                        break;
                    case GeometryType.Points:
                        GeoPoints points = geo as GeoPoints;
                        strRt += TranGeoJson.TransPoints(points);
                        break;
                    case GeometryType.VarLine:
                        GeoVarLine lin = geo as GeoVarLine;
                        strRt += TranGeoJson.TransLin(lin);
                        break;
                    case GeometryType.Lines:
                        GeoLines lins = geo as GeoLines;
                        strRt += TranGeoJson.TransLins(lins);
                        break;
                    case GeometryType.Polygon:
                        GeoPolygon polygon = geo as GeoPolygon;
                        strRt += TranGeoJson.TransPolygon(polygon);
                        break;
                    case GeometryType.Polygons:
                        GeoPolygons polygons = geo as GeoPolygons;
                        strRt += TranGeoJson.TransPolygons(polygons);
                        break;
                }
                strRt += ",";
                recordSet.MoveNext();
            }
            recordSet.Dispose();
            return strRt;
        }

        public static string TransACls2GeoJson(AnnotationCls acls)
        {
            if (acls == null)
                return "";
            string strRt = "";
            QueryDef qd = new QueryDef();
            qd.CursorType = SetCursorType.ForwardCacheSpa;
            RecordSet recordSet = acls.Select(qd);
            if (recordSet == null)
                return "";
            recordSet.MoveFirst();
            while (!recordSet.IsEOF)
            {
                IGeometry geo = recordSet.Geometry;
                if (geo is TextAnno)
                {
                    TextAnno annoText = geo as TextAnno;
                    strRt += TranGeoJson.TransText(annoText);
                }
                strRt += ",";
                recordSet.MoveNext();
            }
            recordSet.Dispose();
            return strRt;
        }

        public static string TransSRSNameByXml(string srs, bool bEpsg)
        {
            if (string.IsNullOrEmpty(srs))
                return "";
            XmlDocument doc = new XmlDocument();
            String projectName = Assembly.GetExecutingAssembly().GetName().Name.ToString();
            Stream sm = Assembly.GetExecutingAssembly().GetManifestResourceStream(projectName + ".CRSConfig.xml");
            doc.Load(sm);
            XmlNode node = doc.SelectSingleNode("CRSCollection/CRSObject");
            if (node == null)
                return "";
            XmlNodeList nodes = node.ChildNodes;
            int nCount = nodes.Count;
            for (int i = 0; i < nCount; i++)
            {
                string ep = nodes[i]["EPSGCodeID"].InnerText;
                string des = nodes[i]["Description"].InnerText;
                if (bEpsg)
                {
                    if (string.Compare(ep, srs, true) == 0)
                        return des;
                }
                else
                {
                    if (string.Compare(des, srs, true) == 0)
                        return ep;
                }
            }
            return "";
        }
        public static int lg10(double value)
        {
            value = Math.Log10(value);
            if (value < -1E-12)
            {
                return (int)(value - 1);
            }
            else
            {
                return (int)value;
            }
        }
        public static double AdjustGridSpace(double dRange) //度 返回DMS
        {
            dRange /= 5;
            double space = Math.Pow(10.0, (int)lg10(dRange));
            dRange /= space;
            if (dRange < 2)
                space *= 1;
            else if (dRange < 5)
                space *= 2;
            else
                space *= 5;

            return AngleConvert.DToDMS(space);
        }
    }
}
